package config

import (
	"fmt"
	"net"
	"os"
	"time"
)

// PortConfig 端口配置结构
type PortConfig struct {
	Port         int    `yaml:"port" json:"port"`
	Host         string `yaml:"host" json:"host"`
	AutoScan     bool   `yaml:"auto_scan" json:"auto_scan"`
	ScanRange    int    `yaml:"scan_range" json:"scan_range"`
	CheckTimeout int    `yaml:"check_timeout" json:"check_timeout"`
}

// DefaultPortConfig 默认端口配置
func DefaultPortConfig() *PortConfig {
	return &PortConfig{
		Port:         8765,
		Host:         "localhost",
		AutoScan:     true,
		ScanRange:    10, // 扫描8766-8775
		CheckTimeout: 3,  // 3秒超时
	}
}

// PortManager 端口管理器
type PortManager struct {
	config *PortConfig
}

// NewPortManager 创建端口管理器
func NewPortManager(config *PortConfig) *PortManager {
	if config == nil {
		config = DefaultPortConfig()
	}
	return &PortManager{config: config}
}

// ResolvePort 解析可用端口
// 优先级：命令行参数 > 配置文件 > 默认值
func (pm *PortManager) ResolvePort(cmdPort int, configPort int) (int, error) {
	var targetPort int

	// 1. 命令行参数优先级最高
	if cmdPort > 0 {
		targetPort = cmdPort
		fmt.Printf("[INFO] 使用命令行指定端口: %d\n", targetPort)
	} else if configPort > 0 {
		// 2. 配置文件端口
		targetPort = configPort
		fmt.Printf("[INFO] 使用配置文件端口: %d\n", targetPort)
	} else {
		// 3. 默认端口
		targetPort = pm.config.Port
		fmt.Printf("[INFO] 使用默认端口: %d\n", targetPort)
	}

	// 验证端口范围
	if err := pm.validatePortRange(targetPort); err != nil {
		return 0, err
	}

	// 检查端口可用性
	if pm.isPortAvailable(targetPort) {
		fmt.Printf("[SUCCESS] 端口 %d 可用\n", targetPort)
		return targetPort, nil
	}

	// 端口被占用，尝试自动扫描
	if pm.config.AutoScan {
		fmt.Printf("[WARNING] 端口 %d 被占用，正在扫描可用端口...\n", targetPort)
		return pm.scanAvailablePort(targetPort)
	}

	// 不允许自动扫描，返回错误
	occupyingProcess := pm.getPortOccupyingProcess(targetPort)
	return 0, fmt.Errorf("端口 %d 被占用%s，请使用其他端口或终止占用进程",
		targetPort, occupyingProcess)
}

// validatePortRange 验证端口范围
func (pm *PortManager) validatePortRange(port int) error {
	if port < 1 || port > 65535 {
		return fmt.Errorf("端口号必须在 1-65535 范围内，当前: %d", port)
	}

	// 检查是否需要管理员权限
	if port < 1024 {
		fmt.Printf("[WARNING] 端口 %d 需要管理员权限\n", port)
		fmt.Println("[INFO] Windows: 请右键选择'以管理员身份运行'")
		fmt.Println("[INFO] Linux/macOS: 请使用 sudo 运行")
	}

	return nil
}

// isPortAvailable 检查端口是否可用
func (pm *PortManager) isPortAvailable(port int) bool {
	timeout := time.Duration(pm.config.CheckTimeout) * time.Second

	// 检查TCP端口
	tcpAddr := fmt.Sprintf("%s:%d", pm.config.Host, port)
	conn, err := net.DialTimeout("tcp", tcpAddr, timeout)
	if err == nil {
		conn.Close()
		return false // 端口被占用
	}

	// 尝试监听端口
	listener, err := net.Listen("tcp", tcpAddr)
	if err != nil {
		return false // 无法监听，端口被占用或权限不足
	}
	listener.Close()

	return true // 端口可用
}

// scanAvailablePort 扫描可用端口
func (pm *PortManager) scanAvailablePort(startPort int) (int, error) {
	fmt.Printf("[INFO] 扫描范围: %d-%d\n", startPort+1, startPort+pm.config.ScanRange)

	for i := 1; i <= pm.config.ScanRange; i++ {
		candidatePort := startPort + i

		// 验证端口范围
		if candidatePort > 65535 {
			break
		}

		if pm.isPortAvailable(candidatePort) {
			fmt.Printf("[SUCCESS] 找到可用端口: %d\n", candidatePort)
			return candidatePort, nil
		}

		fmt.Printf("[INFO] 端口 %d 被占用，继续扫描...\n", candidatePort)
	}

	return 0, fmt.Errorf("在范围 %d-%d 内未找到可用端口",
		startPort+1, startPort+pm.config.ScanRange)
}

// getPortOccupyingProcess 获取占用端口的进程信息
func (pm *PortManager) getPortOccupyingProcess(port int) string {
	// 尝试获取占用进程信息（跨平台实现）
	if processInfo := pm.getProcessByPort(port); processInfo != "" {
		return fmt.Sprintf(" (被进程 %s 占用)", processInfo)
	}
	return ""
}

// getProcessByPort 根据端口获取进程信息
func (pm *PortManager) getProcessByPort(port int) string {
	// Windows实现
	if isWindows() {
		return pm.getWindowsProcessByPort(port)
	}

	// Unix/Linux实现
	return pm.getUnixProcessByPort(port)
}

// isWindows 检查是否为Windows系统
func isWindows() bool {
	return os.PathSeparator == '\\'
}

// getWindowsProcessByPort Windows下获取占用端口的进程
func (pm *PortManager) getWindowsProcessByPort(port int) string {
	// 使用netstat命令查找占用进程
	// 这里简化实现，实际可以使用更复杂的WinAPI调用
	return "未知进程"
}

// getUnixProcessByPort Unix/Linux下获取占用端口的进程
func (pm *PortManager) getUnixProcessByPort(port int) string {
	// 使用lsof或netstat命令查找占用进程
	// 这里简化实现，实际可以执行系统命令
	return "未知进程"
}

// GetPortStatus 获取端口状态信息
func (pm *PortManager) GetPortStatus(port int) map[string]interface{} {
	status := map[string]interface{}{
		"port":      port,
		"host":      pm.config.Host,
		"available": pm.isPortAvailable(port),
		"timestamp": time.Now().Format("2006-01-02 15:04:05"),
	}

	if !status["available"].(bool) {
		status["occupying_process"] = pm.getPortOccupyingProcess(port)
	}

	return status
}

// UpdateConfig 更新端口配置
func (pm *PortManager) UpdateConfig(config *PortConfig) {
	if config != nil {
		pm.config = config
	}
}
